package repl

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"strings"

	"gitee.com/chuanjinge/go-interpreter-waiig/src/monkey/compiler"
	"gitee.com/chuanjinge/go-interpreter-waiig/src/monkey/evaluator"
	"gitee.com/chuanjinge/go-interpreter-waiig/src/monkey/lexer"
	"gitee.com/chuanjinge/go-interpreter-waiig/src/monkey/object"
	"gitee.com/chuanjinge/go-interpreter-waiig/src/monkey/parser"
	"gitee.com/chuanjinge/go-interpreter-waiig/src/monkey/vm"
)

// 以解释器的方式执行代码
// 从输入的源代码中读取，直到读完一行代码，将读取的代码行传递给词法分析器实例，然后输出词法分析器生成的词法单元，直到遇到EOF
// 源代码->词法序列->抽象语法树->解释器解释语法树节点为go对象然后执行加减乘除
func Start(in io.Reader, out io.Writer) {
	// 逐行读取
	scanner := bufio.NewScanner(in)

	env := object.NewEnvironment()
	for {
		fmt.Fprintf(out, ">>")
		// Scan 方法尝试读取下一个 “token”（默认按行切分，即将输入流按换行符分隔成不同部分 ），
		// 当没有输入时，它会暂停程序执行，等待用户在终端输入内容，直到检测到换行符，完成一次读取才继续后续流程。
		scanned := scanner.Scan()
		if !scanned {
			return // 输入流被中断，一般是CTRL+C或者CTRL+D或者CTRL+Z导致的
		}

		line := scanner.Text()
		_, err := handleInput(line, out, env)
		if err != nil {
			continue
		}
	}
}

// 以编译的方式执行输入代码
// 源代码->词法序列->抽象语法树->编译为字节码->虚拟机执行字节码(其实是基于常量池中的go对象的value进行加减乘除)
func StartCompile(in io.Reader, out io.Writer) {
	// 逐行读取
	scanner := bufio.NewScanner(in)
	// 为了防止每次循环
	symbolTable := compiler.NewSymbolTable()
	constants := make([]object.Object, 0)
	globals := make([]object.Object, vm.GloablSize)
	for {
		fmt.Fprintf(out, ">>")
		// Scan 方法尝试读取下一个 “token”（默认按行切分，即将输入流按换行符分隔成不同部分 ），
		// 当没有输入时，它会暂停程序执行，等待用户在终端输入内容，直到检测到换行符，完成一次读取才继续后续流程。
		scanned := scanner.Scan()
		if !scanned {
			return // 输入流被中断，一般是CTRL+C或者CTRL+D或者CTRL+Z导致的
		}

		line := scanner.Text()
		// 将读到的源代码交由 词法分析->语法分析->编译为字节码和计算常量->运行字节码
		l := lexer.New(line)
		p := parser.New(l)
		program := p.ParseProgram()
		if len(p.Errors()) != 0 {
			fmt.Fprintln(out, p.Errors())
			continue
		}

		// 以上动作 编译和解释器都需要
		// 开始编译
		comp := compiler.NewWithState(symbolTable, constants)
		err := comp.Compile(program)
		if err != nil {
			fmt.Fprintf(out, "compilation failed: \n %s \n", err)
			continue
		}

		// 开始执行字节码
		machine := vm.NewWithState(comp.Bytecode(), globals)
		err = machine.Run()
		if err != nil {
			fmt.Fprintf(out, "execute bytecode failed: \n %s \n", err)
			continue
		}

		// 使用执行结果
		obj := machine.LastPoppedStackElem()
		io.WriteString(out, obj.Inspect())
		io.WriteString(out, "\n")
	}
}

func handleInput(input string, out io.Writer, env *object.Environment) (string, error) {
	// 将input两端的空白字符干掉
	input = strings.TrimSpace(input)
	if len(input) == 1 && input == "\n" {
		return "", nil
	}
	// 检测到控制字符暂不处理
	// 控制字符通常指的是ASCII码值小于32或等于127的字符（不包括换行和回车），以及一些特定的高ASCII码字符。
	// 比如：退格（Backspace）是ASCII码8。
	// for i := 0; i < len(input); i++ {
	// 	if input[i] <= 31 || input[i] == 127 { // 检测ASCII控制字符
	// 		fmt.Printf("Control character found: %d\n", input[i])
	// 		os.Exit(1)
	// 	}
	// }
	l := lexer.New(input)

	// 逐个去查找token(词法单元)，直到EOF的出现
	// for token := l.NextToken(); token.Type != tok.EOF; token = l.NextToken() {
	// 	fmt.Fprintf(out, "%+v\n", token)
	// }
	// 250114 修改为语法分析结果
	p := parser.New(l)
	program := p.ParseProgram()
	if len(p.Errors()) != 0 {
		for _, msg := range p.Errors() {
			io.WriteString(out, "\t"+msg+"\n")
		}
		return "", errors.New("something wrong")
	}

	// 将语法分析的结果执行evaluated运算
	evaluated := evaluator.Eval(program, env)
	if evaluated != nil {
		io.WriteString(out, evaluated.Inspect())
		io.WriteString(out, "\n")
		return program.String(), nil
	}
	return "", fmt.Errorf("evaluated error")
}
